#include "widget.h"
#include "ui_widget.h"

#include <QSerialPortInfo>
#include <QDebug>
#include <QMessageBox>
#include <QFileDialog>
#include <QDateTime>
#include <QThread>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setLayout(ui->gridLayoutGlobal);

    //窗口中加入串口控制对象
    serialport = new QSerialPort(this);

    //控制参数初始化
    writeCntTotal = 0;
    readCntTotal = 0;
    serialStatus = false;
    buttonIndex = 0;//控制多文本循环定时发送时下标位置

    //控件初始化
    ui->btnSendContext->setEnabled(false);
    ui->checkBoxSendinTime->setEnabled(false);
    ui->checkBoxSendnewLine->setEnabled(false);
    ui->checkBoxHexSend->setEnabled(false);
    ui->comboBox_boautrate->setCurrentIndex(1);
    ui->comboBox_databit->setCurrentIndex(3);
    ui->checkBox_send->setEnabled(false);
    ui->btnSave->setEnabled(false);
    ui->btnLoad->setEnabled(false);
    ui->btnInit->setEnabled(false);
    ui->pushButton_1->setEnabled(false);
    ui->pushButton_2->setEnabled(false);
    ui->pushButton_3->setEnabled(false);
    ui->pushButton_4->setEnabled(false);
    ui->pushButton_5->setEnabled(false);
    ui->pushButton_6->setEnabled(false);
    ui->pushButton_7->setEnabled(false);
    ui->pushButton_8->setEnabled(false);
    ui->pushButton_9->setEnabled(false);

    //让程序打开时尽快显示时间的同时不加快时间的刷新频率，减少负担
    time_reflash();

    //定时循环发送计时器
    timer = new QTimer(this);
    connect(timer,&QTimer::timeout,[=](){on_btnSendContext_clicked();});

    //多线程方式实现多文本循环发送
    mythread = new CustomThread(this);
    connect(mythread,&CustomThread::threadTimeout,this,&Widget::buttons_handler);

    //系统时间定时器
    getSysTimeTimer = new QTimer(this);
    getSysTimeTimer->start(1000);
    connect(getSysTimeTimer,&QTimer::timeout,[=](){
        time_reflash();
    });

    //定时器方式实现多文本循环发送
    buttonsConTimer = new QTimer(this);
    connect(buttonsConTimer,&QTimer::timeout,this,&Widget::buttons_handler);

    connect(serialport,&QSerialPort::readyRead,this,&Widget::on_SerialData_ReadyToRead);

    connect(ui->comboBox_serialNum,&MyComboBox::refresh,this,&Widget::refreshSerialName);

    //接收当前所有可用串口,并加入到串口comBox中
    refreshSerialName();

    ui->labelSendStatus->setText("COM is NoOpen");

    for(int i =1;i<=9;i++)
    {
        QString btnName = QString("pushButton_%1").arg(i);
        QPushButton *btn = findChild<QPushButton*>(btnName);
        if(btn)
        {
            btn->setProperty("buttonId",i);
            buttons.append(btn);
            connect(btn,SIGNAL(clicked()),this,SLOT(on_command_button_clicked()));
        }

        QString lineEditName = QString("lineEdit_%1").arg(i);
        QLineEdit *lineEdit = findChild<QLineEdit *>(lineEditName);
        lineEdits.push_back(lineEdit);

        QString checkBoxName = QString("checkBox_%1").arg(i);
        QCheckBox *checkBox = findChild<QCheckBox *>(checkBoxName);
        checkBoxs.push_back(checkBox);
    }

}

Widget::~Widget()
{
    delete ui;
}

//NoParity = 0,
//EvenParity = 2,
//OddParity = 3,
//SpaceParity = 4,
//MarkParity = 5,
//UnknownParity = -1


void Widget::on_btnCtrlSerial_clicked()
{
    if(!serialStatus)
    {
        //1.选择端口号
        serialport->setPortName(ui->comboBox_serialNum->currentText());
        //2.配置波特率
        serialport->setBaudRate(ui->comboBox_boautrate->currentText().toInt());
        //3.配置数据位
        serialport->setDataBits(QSerialPort::DataBits(ui->comboBox_databit->currentText().toInt()));
        //4.配置校验位
        switch (ui->comboBox_checkbit->currentIndex()) {
        case 0:
            serialport->setParity(QSerialPort::NoParity);
            break;
        case 1:
            serialport->setParity(QSerialPort::EvenParity);
            break;
        case 2:
            serialport->setParity(QSerialPort::MarkParity);
            break;
        case 3:
            serialport->setParity(QSerialPort::OddParity);
            break;
        case 4:
            serialport->setParity(QSerialPort::SpaceParity);
            break;
        default:
            serialport->setParity(QSerialPort::UnknownParity);
            break;
        }
        //5.配置停止位
        serialport->setStopBits(QSerialPort::StopBits(ui->comboBox_stopbit->currentText().toInt()));
        //6.流控
        if(ui->comboBox_fileCtrl->currentText() == "None")
            serialport->setFlowControl(QSerialPort::NoFlowControl);
        //7.打开串口
        if(serialport->open(QIODevice::ReadWrite))
        {
            //qDebug() <<"serial open success";
            ui->comboBox_databit->setEnabled(false);
            ui->comboBox_fileCtrl->setEnabled(false);
            ui->comboBox_checkbit->setEnabled(false);
            ui->comboBox_stopbit->setEnabled(false);
            ui->comboBox_serialNum->setEnabled(false);
            ui->comboBox_boautrate->setEnabled(false);
            ui->btnCtrlSerial->setText("关闭串口");
            serialStatus =true;
            ui->btnSendContext->setEnabled(true);
            ui->checkBoxSendinTime->setEnabled(true);
            ui->checkBoxSendnewLine->setEnabled(true);
            ui->checkBoxHexSend->setEnabled(true);

            ui->checkBox_send->setEnabled(true);
            ui->btnSave->setEnabled(true);
            ui->btnLoad->setEnabled(true);
            ui->btnInit->setEnabled(true);
            ui->pushButton_1->setEnabled(true);
            ui->pushButton_2->setEnabled(true);
            ui->pushButton_3->setEnabled(true);
            ui->pushButton_4->setEnabled(true);
            ui->pushButton_5->setEnabled(true);
            ui->pushButton_6->setEnabled(true);
            ui->pushButton_7->setEnabled(true);
            ui->pushButton_8->setEnabled(true);
            ui->pushButton_9->setEnabled(true);


            ui->labelSendStatus->setText(ui->comboBox_serialNum->currentText()+ " isOpen");
        }
        else
        {
            //qDebug() << "Open failed:" << serialport->errorString();
            QMessageBox msgBox;
            msgBox.setWindowTitle("串口打开失败");
            msgBox.setText("打开失败，串口可能被占用或已拔出！");
            msgBox.exec();

            return;
        }
    }else
    {
        serialport->close();
        ui->comboBox_databit->setEnabled(true);
        ui->comboBox_fileCtrl->setEnabled(true);
        ui->comboBox_checkbit->setEnabled(true);
        ui->comboBox_stopbit->setEnabled(true);
        ui->comboBox_serialNum->setEnabled(true);
        ui->comboBox_boautrate->setEnabled(true);
        ui->btnCtrlSerial->setText("打开串口");
        serialStatus = false;
        ui->btnSendContext->setEnabled(false);
        ui->checkBoxSendinTime->setEnabled(false);
        timer->stop();
        ui->checkBoxSendinTime->setCheckState(Qt::Unchecked);
        ui->lineEditSendContext->setEnabled(true);
        ui->lineEditTimeEach->setEnabled(true);

        ui->checkBoxSendnewLine->setEnabled(false);
        ui->checkBoxHexSend->setEnabled(false);
        ui->labelSendStatus->setText(ui->comboBox_serialNum->currentText()+ " isClose");

        ui->checkBox_send->setEnabled(false);
        ui->btnSave->setEnabled(false);
        ui->btnLoad->setEnabled(false);
        ui->btnInit->setEnabled(false);
        ui->pushButton_1->setEnabled(false);
        ui->pushButton_2->setEnabled(false);
        ui->pushButton_3->setEnabled(false);
        ui->pushButton_4->setEnabled(false);
        ui->pushButton_5->setEnabled(false);
        ui->pushButton_6->setEnabled(false);
        ui->pushButton_7->setEnabled(false);
        ui->pushButton_8->setEnabled(false);
        ui->pushButton_9->setEnabled(false);

    }
}

void Widget::on_btnSendContext_clicked()
{
    int writeCnt = 0;
    QByteArray sendData= ui->lineEditSendContext->text().toUtf8();

    if(ui->checkBoxHexSend->isChecked())
    {
        QString tmp = ui->lineEditSendContext->text();
        //1.判断是否是偶数位
        QByteArray tmpArray = tmp.toUtf8();
        if(tmpArray.size()%2!=0)
        {
            ui->labelSendStatus->setText("Error Input！");
            return;
        }
        //2.判断是否是符合16进制表达
        for(unsigned char c : tmpArray)
        {
            if(!std::isxdigit(c))
            {
                ui->labelSendStatus->setText("Error Input！");
                return;
            }

        }

        if(ui->checkBoxSendnewLine->isChecked())
        {
            tmpArray.append("\r\n");
        }

        //3.转换成16进制发送，用户输入1变成1，拒绝变成字符1,ASII 49
        QByteArray arraySend = QByteArray::fromHex(tmpArray);
        writeCnt = serialport->write(arraySend);

    }
    else
    {
        //如果不是16进制发送
        if(ui->checkBoxSendnewLine->isChecked())
        {
            QByteArray arrSendData= sendData;
            arrSendData.append("\r\n");
            writeCnt = serialport->write(arrSendData);
        }
        else
        {
            writeCnt = serialport->write(sendData);
        }
    }

    //发送失败
    if(writeCnt == -1)
    {
        ui->labelSendStatus->setText("Send Error!");
    }
    else
    {
        writeCntTotal +=writeCnt;
        //qDebug() << "SendOK" <<sendData;
        ui->labelSendStatus->setText("Send OK!");
        //ui->labelSentcnt->setNum(writeCntTotal);
        ui->labelSentcnt->setText("Send:"+QString::number(writeCntTotal));
        if(strcmp(sendData,sendBak.toStdString().c_str())!=0)
        {
            ui->textEditRecond->append(sendData);
            sendBak = QString::fromUtf8(sendData);
        }
    }
}

void Widget::on_SerialData_ReadyToRead()
{
    QString revMessage = serialport->readAll();
    if(revMessage != NULL)
    {
        if(ui->checkBLine->isChecked())
        {
            revMessage = revMessage +"\r\n";
        }
        if(ui->checkBHexDisplay->isChecked())
        {
            //读取新内容并HEX化
            QByteArray tmpHexString = revMessage.toUtf8().toHex().toUpper();

            //读出原控件内的内容
            QString tmpStringHex = ui->textEditRev->toPlainText();
            //原本已HEX化的内容加上新内容
            tmpHexString = tmpStringHex.toUtf8() + tmpHexString;
            //重新将全部内容显示在控件上
            ui->textEditRev->setText(QString::fromUtf8(tmpHexString));
        }
        else
        {
            if(ui->checkBRevTime->checkState() == Qt::Unchecked)
            {
                //insertPlainText不会自动换行，append则会
                ui->textEditRev->insertPlainText(revMessage);
                //qDebug() << "getMessage:"<< revMessage;
            }
            else
            {
                getSysTime();
                ui->textEditRev->insertPlainText("【"+myTime+"】"+revMessage);
            }
        }

        readCntTotal +=revMessage.size();
        //ui->labelRevcnt->setNum(readCntTotal);
        ui->labelRevcnt->setText("Received:"+QString::number(readCntTotal));

        //移动光标到最底
        ui->textEditRev->moveCursor(QTextCursor::End);
        ui->textEditRev->ensureCursorVisible();
        //ui->textEditRev->setFocus();//出现问题，当刷新频率过高，光标将争夺不过来，难以点击其他按键
    }
}

void Widget::on_checkBoxSendinTime_clicked(bool checked)
{
    //qDebug() <<"checkBsendIntime:"<<checked;
    if(checked)
    {
        //设置计时器间隔时间
        timer->start(ui->lineEditTimeEach->text().toInt());
        //on_btnSendContext_clicked();
        ui->lineEditSendContext->setEnabled(false);
        ui->lineEditTimeEach->setEnabled(false);
        ui->checkBHexDisplay->setEnabled(false);
        ui->checkBoxHexSend->setEnabled(false);
    }else
    {
        timer->stop();
        ui->lineEditSendContext->setEnabled(true);
        ui->lineEditTimeEach->setEnabled(true);
        ui->checkBHexDisplay->setEnabled(true);
        ui->checkBoxHexSend->setEnabled(true);
    }
}

void Widget::on_btnRevClear_clicked()
{
    ui->textEditRev->clear();
}

void Widget::on_btnRevSave_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                                                    "C:/Users/16014/Desktop",
                                                    tr("Text (*.txt)"));
    if(fileName !=NULL)
    {
        QFile file(fileName);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
            return;

        QTextStream out(&file);
        out << ui->textEditRev->toPlainText();
        file.close();
    }
}

void Widget::time_reflash()
{
    getSysTime();
    ui->labelSendTime->setText(myTime);
}

void Widget::getSysTime()
{
    QDateTime currentTime = QDateTime::currentDateTime();
    QDate date = currentTime.date();
    QTime time = currentTime.time();

    //.arg(具体字符，占位（不足补位），多少数以内，填充字符)
    myTime =  QString("%1-%2-%3 %4:%5:%6")
            .arg(date.year(),2,10,QChar('0'))
            .arg(date.month(),2,10,QChar('0'))
            .arg(date.day(),2,10,QChar('0'))
            .arg(time.hour(),2,10,QChar('0'))
            .arg(time.minute(),2,10,QChar('0'))
            .arg(time.second(),2,10,QChar('0'));
}

void Widget::on_checkBHexDisplay_clicked(bool checked)
{
    if(checked)
    {
        //1.读取textEdit内容
        QString tmp = ui->textEditRev->toPlainText();
        //2.转换成hex
        QByteArray qtmp = tmp.toUtf8();
        qtmp = qtmp.toHex();
        //3.显示
        QString lastShow;
        tmp = QString::fromUtf8(qtmp).toUpper();
        for(int i=0;i<tmp.size();i+=2)
        {
            lastShow += tmp.mid(i,2)+" ";
        }
        ui->textEditRev->setText(lastShow.toUpper());
    }
    else
    {
        QString tmpHexString = ui->textEditRev->toPlainText();
        QByteArray tmpHexQBytearray = tmpHexString.toUtf8();
        tmpHexQBytearray = QByteArray::fromHex(tmpHexQBytearray);
        ui->textEditRev->setText(QString::fromUtf8(tmpHexQBytearray));
    }
    ui->textEditRev->moveCursor(QTextCursor::End);
    ui->textEditRev->ensureCursorVisible();
}

void Widget::on_btnHideTable_clicked(bool checked)
{
    if(checked)
    {
        ui->btnHideTable->setText("拓展面板");
        ui->groupBoxTexts->hide();
    }
    else
    {
        ui->btnHideTable->setText("隐藏面板");
        ui->groupBoxTexts->show();
    }

}

void Widget::on_btnHideHistory_clicked(bool checked)
{
    if(checked)
    {
        ui->btnHideHistory->setText("拓展历史");
        ui->groupBoxRecond->hide();
    }
    else
    {
        ui->btnHideHistory->setText("隐藏历史");
        ui->groupBoxRecond->show();
    }
}

void Widget::refreshSerialName()
{
    ui->comboBox_serialNum->clear();
    //检测系统可用串口，并更新到combobox上
    QList<QSerialPortInfo> serialList = QSerialPortInfo::availablePorts();
    for(auto c : serialList)
    {
        //qDebug() << c.portName();
        ui->comboBox_serialNum->addItem(c.portName());
    }
    ui->labelSendStatus->setText("Com Refresh!");
}

void Widget::on_command_button_clicked()
{
    //qobject_cast可以让派生类之间进行安全的转换,sender获取发送者
    QPushButton *btn = qobject_cast<QPushButton *>(sender());
    if(btn)
    {
        //通过构造函数中给btn所附加的属性num来查找对应的lindEdit和checkBox
        int num = btn->property("buttonId").toInt();
        QString lineEditName = QString("lineEdit_%1").arg(num);
        QLineEdit *lineEdit = findChild<QLineEdit*>(lineEditName);
        if(lineEdit)
        {
            if(lineEdit->text().size()<=0)
            {
                return;
            }
            else
            {
                ui->lineEditSendContext->setText(lineEdit->text());
            }
        }

        QString checkBoxName = QString("checkBox_%1").arg(num);
        QCheckBox *checkBox = findChild<QCheckBox*>(checkBoxName);
        if(checkBox)
            ui->checkBoxHexSend->setChecked(checkBox->isChecked());
        on_btnSendContext_clicked();
    }
}


void Widget::buttons_handler()
{
    if(buttonIndex < buttons.size())
    {
        QPushButton *btnTmp = buttons[buttonIndex];
        emit btnTmp->clicked();
        buttonIndex++;
    }
    else
    {
        buttonIndex = 0;
    }

    //QThread::msleep(ui->spinBox->text().toUInt());//不能在QT的UI线程中延迟，否则导致页面刷新问题
}


void Widget::on_checkBox_send_clicked(bool checked)
{
    if(checked)
    {
        ui->spinBox->setEnabled(false);
        //开启定时器
        //buttonsConTimer->start(ui->spinBox->text().toUInt());
        mythread->setsendInterTime(ui->spinBox->text().toInt());

        //开启线程
        mythread->start();
    }
    else
    {
        ui->spinBox->setEnabled(true);
        //关闭定时器
        //buttonsConTimer->stop();

        //关闭线程
        mythread->terminate();
    }
}

void Widget::on_btnInit_clicked()
{
    QMessageBox msgBox;
    msgBox.setWindowTitle("提示");
    msgBox.setIcon(QMessageBox::Warning);
    msgBox.setText("重置列表不可逆，是否重置？");
    //msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);

    QPushButton *yesButton = msgBox.addButton("是",QMessageBox::YesRole);
    QPushButton *noButton = msgBox.addButton("否",QMessageBox::NoRole);
    msgBox.exec();
    if(msgBox.clickedButton() == yesButton)
    {
        //遍历lineEdit并清空
        for(QLineEdit *c : lineEdits)
        {
            c->clear();
        }

        //遍历checkBox并取消勾选
        for(QCheckBox *c:checkBoxs)
        {
            c->setCheckState(Qt::Unchecked);
        }

    }
    else if(msgBox.clickedButton() == noButton)
    {

    }
}

void Widget::on_btnSave_clicked()
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                                                    "C:/Users/16014/Desktop",
                                                    tr("Text (*.txt)"));
    QFile file(fileName);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        return;
    }

    QTextStream out(&file);
    for(int i =0;i<lineEdits.size();i++)
    {
        out<<checkBoxs[i]->isChecked() << ","<<lineEdits[i]->text()<<"\n";
    }
    file.close();

}

void Widget::on_btnLoad_clicked()
{
    int i =0;
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
                                                    "C:/Users/16014/Desktop",
                                                    tr("Text (*.txt)"));
    if(fileName !=NULL)
    {
        QFile file(fileName);
        if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            return;
        }

        QTextStream in(&file);
        while(!in.atEnd()&&i < 9)
        {
            QString line = in.readLine();
            //通过调用split依据逗号将原本字符串分割，并返回一个QStringList数组
            QStringList parts = line.split(",");
            if(parts.count() == 2)
            {
                checkBoxs[i]->setChecked(parts[0].toInt());
                lineEdits[i]->setText(parts[1]);
            }
            i++;
        }

    }

}
